﻿using Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows;
using Prism.Events;
using DryIoc;
using AIVision.PLC.LiWi;
using AIVision.Model.MachineModels;
using AIVision.Model.EntityModels;
using AIVision.PLC.MachineModule;
using Prism.Ioc;
using AIVision.Model.UIModels;
using System.Drawing;
using System.Threading;
using System.Diagnostics;
using System.Windows.Interop;
using AIVision.Model.Events;
using AIVision.Repository.Services;
using AIVision.Model.InspectModels;

namespace AIVision.PLC
{
    public class Machine
    {
        private readonly IEventAggregator eventAggregator;
        private readonly MachineStatusModel machineStatus;
        private readonly SummaryDataModel viewDataModel;
        private readonly InspectStatusModel inspectStatus;

        public TuLun TuLun { get; }
        public PPU PPU { get;}
        public ChaHe ChaHe { get; }
        public FeiLiao FeiLiao { get; }
        public ZhuanTai ZhuanTai { get; }
        protected IntPtr _handle = IntPtr.Zero;
        protected PLCConfigDto PLCConfig { get; set; }

        public bool IsInitOK { get; set; } = false;

        public bool EmergencyStopXH
        {
            get
            {
                uint in38 = 2;
                LiWi.Shell.PMC_GetIn(_handle,38, ref in38);

                return in38 == 0;
            }
        }
        public bool StartXH
        {
            get
            {
                uint in39 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 39, ref in39);
                return in39 == 1;
            }
        }
        public bool StopXH
        {
            get
            {
                uint in40 = 0;
                LiWi.Shell.PMC_GetIn(_handle, 40, ref in40);
                return in40 == 1;
            }
        }

        protected Task mainTask,autoRunTask1=new Task(() => { }), autoRunTask2= new Task(() => { });
        public Machine(IEventAggregator eventAggregator,MachineStatusModel machineStatus, SummaryDataModel viewDataModel, InspectStatusModel inspectStatus, TuLun tuLun, PPU ppu,ZhuanTai zhuanTai,ChaHe chaHe,FeiLiao feiLiao )
        {
            this.eventAggregator = eventAggregator;
            this.machineStatus = machineStatus;
            this.viewDataModel = viewDataModel;
            this.inspectStatus = inspectStatus;
            this.TuLun = tuLun;
            this.PPU = ppu;
            this.ZhuanTai = zhuanTai;
            ChaHe = chaHe;
            FeiLiao = feiLiao;
        }
        /// <summary>
        /// 初始化运动控制链接，并启动设备主任务线程
        /// </summary>
        /// <param name="plcConfig"></param>
        public void InitConnection(PLCConfigDto plcConfig)
        {
            if (IsInitOK)
                return;
            this.PLCConfig = plcConfig;
        
            try
            {
                Shell.PMC_Close(_handle);
                _handle = IntPtr.Zero;
                int result = Shell.PMC_OpenEth(plcConfig.IP, ref _handle);
                if (result != Shell.ERR_SUCCESS)
                    eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"不能连接到服务器!", "Red"));
                else
                {
                    eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"PLC链接成功!", "Green"));
                    TuLun.Init(_handle, PLCConfig);
                    PPU.Init(_handle, PLCConfig);
                    ZhuanTai.Init(_handle, PLCConfig);
                    ChaHe.Init(_handle, PLCConfig);
                    FeiLiao.Init(_handle, PLCConfig);
                    mainTask = new Task(MainTask);
                    mainTask.Start();
                    IsInitOK = true;
                    //链接成功后打开黄灯
                    LiWi.Shell.PMC_SetOp(_handle, 22, 1);  //打开黄灯
                    LiWi.Shell.PMC_SetOp(_handle, 21, 0);  // 关闭绿灯
                    LiWi.Shell.PMC_SetOp(_handle, 23, 0);  //关闭红灯
                    LiWi.Shell.PMC_SetOp(_handle, 35, 1);  // 关闭直振
                }
            }
            catch (Exception ex)
            {
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"不能连接到服务器{ex.Message}!", "Red"));
            }
        }

        /// <summary>
        /// Machine主任务，链接控制器成功后开始以独立线程执行
        /// </summary>
        private void MainTask()
        {
            while (true)
            {
                //急停按钮逻辑，如果急停信号发生变化，出发对应的动作
                if(machineStatus.EmergencyStopXH != EmergencyStopXH)
                {
                    machineStatus.EmergencyStopXH = EmergencyStopXH;
                    if (EmergencyStopXH)
                        EmergencyStop();
                    else
                        EmergencyStart();

                }
               //启动按钮
                if (StartXH && !machineStatus.AutoRunStatus)
                {
                    AutoRunStart();
                    eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"连续运行任务启动!", "Green"));
                }
                   
                //停止按钮
                if(StopXH && machineStatus.AutoRunStatus)
                {
                    machineStatus.AutoRunStatus = false;
                    //AutoRunStop();
                    eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"连续运行任务停止，手动停止!", "Green"));
                }
                    


                if (machineStatus.EnableMonitor)
                {
                    ZhuanTai.MonitorStatus();
                    PPU.MonitorStatus();
                    TuLun.MonitorStatus();
                    ChaHe.MonitorStatus();
                    FeiLiao.MonitorStatus();
                }
            }
        }


        #region 连续运行启动、停止、运行过程Task
        public void AutoRunStart()
        {
            if (!machineStatus.AutoRunStatus && machineStatus.ResetLocationStatus && autoRunTask1.Status != TaskStatus.Running && autoRunTask2.Status != TaskStatus.Running)
            {
                machineStatus.AutoRunStatus = true;
                inspectStatus.VisionInspectComplete = true;
                machineStatus.OkProductDownCompleteFlag = false;
                machineStatus.NGProductDownCompleteFlag = false;
                CTS = new CancellationTokenSource();
                autoRunTask1 = new Task(LoopRunTask,CTS.Token);
                autoRunTask1.Start();
                CTS2 = new CancellationTokenSource();
                autoRunTask2 = new Task(LoopRunTask2, CTS2.Token);
                autoRunTask2.Start();

                LiWi.Shell.PMC_SetOp(_handle, 22, 0);  //关闭黄灯
                LiWi.Shell.PMC_SetOp(_handle, 20, 0);  //关闭蜂鸣器
                LiWi.Shell.PMC_SetOp(_handle, 21, 1);  // 打开绿灯
                LiWi.Shell.PMC_SetOp(_handle, 35, 0);  //打开直振
            }
            else
            {
                if(machineStatus.AutoRunStatus)
                    eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"设备运行中", "Red"));
                if (!machineStatus.ResetLocationStatus)
                    eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"设备未复位", "Red"));
            }
        }
        public void AutoRunStop()
        {
            machineStatus.AutoRunStatus = false;
            CTS.Cancel();
            CTS2.Cancel();
            LiWi.Shell.PMC_SetOp(_handle, 22, 1);  //打开黄灯
            LiWi.Shell.PMC_SetOp(_handle, 20, 1);  //打开蜂鸣器
            LiWi.Shell.PMC_SetOp(_handle, 21, 0);  // 关闭绿灯
            LiWi.Shell.PMC_SetOp(_handle, 35, 1);  //关闭直振
        }

        private void LoopRunTask()
        {
            while (machineStatus.AutoRunStatus && !machineStatus.CompleteInspect)
            {
                try
                {
                    //凸轮开
                    CTS.Token.ThrowIfCancellationRequested();
                    if (TuLun.ShangLiaoXH && TuLun.TuLunGuanXH && !PPU.QuLiaoLocation)
                        TuLun.RunOpenAsync();
                    //凸轮关
                    CTS.Token.ThrowIfCancellationRequested();
                    if (!TuLun.ShangLiaoXH && !TuLun.TuLunGuanXH && !PPU.QuLiaoLocation)
                        TuLun.RunCloseAsync();

                    //PPU取料
                    CTS.Token.ThrowIfCancellationRequested();
                    if (TuLun.ShangLiaoXH && !TuLun.TuLunGuanXH && PPU.QuLiaoWaitLocation)
                        PPU.RunQuLiaoAsync();
                }
                catch (OperationCanceledException)
                {
                    AutoRunStop();
                }
            }
        }



        //int fangliaocishu = 0, chahecishu = 0,fenliaocishu=0,paizhaocishu=0, xuanzhuancishu = 0;
        private void LoopRunTask2()
        {
            bool b = false;
            while (machineStatus.AutoRunStatus)
            {
                try
                {
                    if(StopXH)
                    {
                        AutoRunStop();
                    }
                    //收料逻辑
                    if (machineStatus.CompleteInspect)
                    {
                       
                        if(machineStatus.VirtuallyXHCount<8)
                        {
                            machineStatus.VirtuallyXHCount += 1;
                            machineStatus.VirtuallyZhuanTaiShangLiaoXH = true;
                        }
                        else
                        {
                            ChaHe.ChaHeYStep();
                            machineStatus.VirtuallyXHCount = 0;
                            machineStatus.CompleteInspect = false;
                            AutoRunStop();
                            eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"检查完成,设备停止.", "Red"));
                        }
                    }
                        

                    //等待ppu放料条件满足

                    timeout = 0;
                    b = false;
                    //Trace.WriteLine($"步骤1：等待放料");
                    while (!b)
                    {
                        b = (PPU.FangLiaoWaitLocation  && !ZhuanTai.ServoRunXH) || machineStatus.CompleteInspect;
                        WaitTimeout2(PLCConfig.RunWaitTimeCount, "等待PPU放料");
                    }
                    if (!machineStatus.VirtuallyZhuanTaiShangLiaoXH)
                    {
                        //Trace.WriteLine($"步骤1：执行放料");
                        PPU.RunFangLiaoAsync();
                        viewDataModel.FangLiaoQty += 1;
                    }
                        
                    
                    timeout = 0;
                    b = false;
                    //Trace.WriteLine($"步骤1：等待放料完成");
                    while (!b)
                    {
                        b = ZhuanTai.ShangLiaoXH || machineStatus.VirtuallyZhuanTaiShangLiaoXH;
                        WaitTimeout2(PLCConfig.RunWaitTimeCount, "等待转台上料完成");
                    }
                        


                    //等待插盒条件满足、包括视觉检查完成
                    timeout = 0;
                    b = false;
                    //Trace.WriteLine($"步骤2：等待插盒");
                    while (!b)
                    {
                        b = !ZhuanTai.ServoRunXH && inspectStatus.VisionInspectComplete
                              && ChaHe.QuLiaoUpXH && ChaHe.XLocation == 0 && !machineStatus.OkProductDownCompleteFlag;
                        WaitTimeout2(PLCConfig.RunWaitTimeCount, "等待插盒");
                    }
                    //Trace.WriteLine($"检测完成状态{inspectStatus.VisionInspectComplete}");

                    //Trace.WriteLine($"OK料信号：{inspectStatus.OKLiao}");
                    //Trace.WriteLine($"OK料位置信号:{ZhuanTai.OKLiaoXH}");
                    //插盒-根据料OK，NG判断是否插盒，最终置位OkProductDownCompleteFlag
                    if (inspectStatus.OKLiao && ZhuanTai.OKLiaoXH)
                    {
                        //Trace.WriteLine($"OK料下料");
                        //Trace.WriteLine($"步骤2：执行插盒");
                        ChaHe.RunAsync();
                        viewDataModel.ChaHeQty += 1;
                        //换盒，插每盒最后一个，等待换盒完成在继续
                        if (ChaHe.YLocation == 10 && ChaHe.XRecordLocation == 20)
                        {
                            timeout = 0;
                            while (ChaHe.XLocation == 0)
                                WaitTimeout2(PLCConfig.RunWaitTimeCount);
                        }
                    }
                    machineStatus.OkProductDownCompleteFlag = true;


                    //等待废料条件满足
                    timeout = 0;
                    b = false;
                    //Trace.WriteLine($"步骤3：等待废料");
                    while (!b)
                    {
                        b = !ZhuanTai.ServoRunXH && FeiLiao.Location == 2 && !machineStatus.NGProductDownCompleteFlag;
                        WaitTimeout2(PLCConfig.RunWaitTimeCount, "等待废料");
                    }
                    //如果废料XH存在就下废料
                    if (ZhuanTai.NGLiaoXH)
                    {
                        //Trace.WriteLine($"步骤3：执行废料");
                        FeiLiao.RunAsync();
                        viewDataModel.FeiLiaoQty += 1;
                    }
                    machineStatus.NGProductDownCompleteFlag = true;





                    //触发拍照
                    if (machineStatus.OkProductDownCompleteFlag && machineStatus.NGProductDownCompleteFlag)
                    {
                       //Trace.WriteLine($"步骤4：触发拍照");
                        inspectStatus.VisionPhotoComplete = false;
                        inspectStatus.VisionInspectComplete = false;
                        inspectStatus.VisionPhotoReady = true;
                        viewDataModel.ChuFaPaiZhaoQty += 1;
                    }

                    //等待旋转条件满足-包括拍照完成
                    timeout = 0;
                    b = false;
                    //Trace.WriteLine($"步骤5：等待旋转");
                    while (!b)
                    {
                        b = !PPU.FangLiaoXH && (ZhuanTai.ShangLiaoXH || machineStatus.VirtuallyZhuanTaiShangLiaoXH)
                        && !ZhuanTai.ServoRunXH && !ZhuanTai.NGLiaoXH && ChaHe.QuLiaoUpXH
                       && inspectStatus.VisionPhotoComplete;
                        WaitTimeout2(PLCConfig.RunWaitTimeCount, "等待旋转");
                    }
                    //开始转
                    //Trace.WriteLine($"步骤5：执行旋转");
                    ZhuanTai.Run();
                    //Trace.WriteLine($"步骤5：旋转完成，清理各信号");
                    viewDataModel.XuanZhuanQty += 1;
                    //转台到位
                    machineStatus.OkProductDownCompleteFlag = false;
                    machineStatus.NGProductDownCompleteFlag = false;
                    //收料，旋转之后清楚上料信号
                    if (machineStatus.CompleteInspect)
                        machineStatus.VirtuallyZhuanTaiShangLiaoXH = false;


                    //Trace.WriteLine($"周期结束——放料{fangliaocishu},拍照{paizhaocishu},旋转{xuanzhuancishu}");
                }
                catch (OperationCanceledException ex)
                {
                    AutoRunStop();
                }
            }
            AutoRunStop();
        }

       
        



        #endregion
        public void CompleteInspect()
        {
            machineStatus.CompleteInspect = true;
        }
        public void ClosedBuzzer()
        {
            LiWi.Shell.PMC_SetOp(_handle, 20, 0);  //关闭蜂鸣器
        }
        public void ResetLocation()
        {
            Task t = new Task(ResetLocationMethod, CTS3.Token);
            t.Start();
        }
        private void ResetLocationMethod()
        {
            try
            {
                FeiLiao.ResetLocationAsync();
                Task.Delay(100).Wait();
                while (FeiLiao.RunTask.Status == TaskStatus.Running)
                    WaitTimeout3(10000);
                ZhuanTai.ResetLocation();
                //Task.Delay(1000).Wait();
                TuLun.ResetLocationAsync();
                while (TuLun.RunTask.Status == TaskStatus.Running)
                    WaitTimeout3(10000);
                //Task.Delay(1000).Wait();
                PPU.ResetLocationAsync();
                while (PPU.RunTask.Status == TaskStatus.Running)
                    WaitTimeout3(10000);
                //Task.Delay(1000).Wait();
                ChaHe.ResetXLocationAsync();
                while (ChaHe.RunTask.Status == TaskStatus.Running)
                    WaitTimeout3(10000);
                ChaHe.ResetYLocation();

                machineStatus.ResetLocationStatus = true;
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"位置复位成功!", "Green"));
            }
            catch (OperationCanceledException ex)
            {

            }
        }

        #region 急停方法
        public void EmergencyStart()
        {
            Shell.PMC_SetAxisEnable(_handle, 0, 1);
            Shell.PMC_SetAxisEnable(_handle, 1, 1);
            Shell.PMC_SetAxisEnable(_handle, 2, 1);
            Shell.PMC_SetAxisEnable(_handle, 3, 0);
            Shell.PMC_SetAxisEnable(_handle, 4, 0);
            Shell.PMC_SetAxisEnable(_handle, 5, 1);
            LiWi.Shell.PMC_SetOp(_handle, 23, 0);  //关闭红灯
            ZhuanTai.CTS = new CancellationTokenSource();
        }
        public void EmergencyStop()
        {
            if (machineStatus.AutoRunStatus)
            {
                machineStatus.AutoRunStatus = false;
            }
            machineStatus.ResetLocationStatus = false;
            //轴
            Shell.PMC_Single_Cancel(_handle, 0, 3);
            Shell.PMC_SetAxisEnable(_handle, 0, 0);

            Shell.PMC_Single_Cancel(_handle, 1, 3);
            Shell.PMC_SetAxisEnable(_handle, 1, 0);

            Shell.PMC_Single_Cancel(_handle, 2, 3);
            Shell.PMC_SetAxisEnable(_handle, 2, 0);

            Shell.PMC_Single_Cancel(_handle, 3, 3);
            Shell.PMC_SetAxisEnable(_handle, 3, 1);

            Shell.PMC_Single_Cancel(_handle, 4, 3);
            Shell.PMC_SetAxisEnable(_handle, 4, 1);

            Shell.PMC_Single_Cancel(_handle, 5, 3);
            Shell.PMC_SetAxisEnable(_handle, 5, 0);
            TuLun.CTS.Cancel();
            PPU.CTS.Cancel();
            ZhuanTai.CTS.Cancel();
            ChaHe.CTS.Cancel();
            FeiLiao.CTS.Cancel();
            LiWi.Shell.PMC_SetOp(_handle, 23, 1);  //打开红灯
            LiWi.Shell.PMC_SetOp(_handle, 35, 0);  //关闭直振
        } 
        #endregion


        #region WaitTimeout
        public CancellationTokenSource CTS { get; set; } = new CancellationTokenSource();
        public CancellationTokenSource CTS2 { get; set; } = new CancellationTokenSource();
        public CancellationTokenSource CTS3 { get; set; } = new CancellationTokenSource();
        public delegate void TimeOutDelegate();
        private int timeout = 0;
        private void WaitTimeout2(int waitTime, string msg = "", TimeOutDelegate timeOutDelegate = null)
        {
            // 检查是否请求取消
            CTS2.Token.ThrowIfCancellationRequested();
            Task.Delay(1).Wait();
            timeout += 1;
            if (timeout > waitTime)
            {
                CTS2.Cancel();
                if (timeOutDelegate != null)
                    timeOutDelegate();
                machineStatus.AutoRunStatus = false;
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"等待超时:{msg}", "Red"));
            }
        }
        private void WaitTimeout3(int waitTime, string msg = "", TimeOutDelegate timeOutDelegate = null)
        {
            // 检查是否请求取消
            CTS3.Token.ThrowIfCancellationRequested();
            Task.Delay(1).Wait();
            timeout += 1;
            if (timeout > waitTime)
            {
                CTS3.Cancel();
                if (timeOutDelegate != null)
                    timeOutDelegate();
                machineStatus.AutoRunStatus = false;
                eventAggregator.GetEvent<PLCRunMsgEvent>().Publish(new RunMsgModel($"等待超时:{msg}", "Red"));
            }
        }
        #endregion
    }
}
